iT邦幫忙

2024 iThome 鐵人賽

DAY 19
0
Mobile Development

SwiftUI快速入門30天系列 第 19

Day19 - @FetchRequest,使用 Core Data 獲取資料

  • 分享至 

  • xImage
  •  

@FetchRequest 使用 Core Data

在 SwiftUI 中,@FetchRequest 是一個非常方便的屬性包裝器(Property Wrapper),用來與 Core Data 整合,並在視圖中自動獲取和顯示資料。這篇教學文將會帶你一步步了解如何使用 @FetchRequest 來從 Core Data 中獲取資料並顯示在 SwiftUI 的畫面上。

1. 準備 Core Data 堆疊

首先,我們假設你已經在專案中啟用了 Core Data。如果還沒有,可以在新建專案時勾選 "Use Core Data" 來自動配置。

Core Data 的主要組件包括 NSManagedObjectModelNSPersistentStoreCoordinatorNSManagedObjectContext 等。這些組件在應用程式啟動時會初始化,通常由 AppDelegate 或 SceneDelegate 管理。現代的 SwiftUI 專案可以使用 PersistenceController 來封裝 Core Data 的堆疊:

import CoreData

struct PersistenceController {
    static let shared = PersistenceController()

    let container: NSPersistentContainer

    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "ModelName") // 替換為你的 Core Data 模型名稱
        if inMemory {
            container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
        }
        container.loadPersistentStores { (description, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    }

    var viewContext: NSManagedObjectContext {
        return container.viewContext
    }
}

2. 定義 Core Data 的 Entity 和屬性

接著,定義你的 Core Data Entity。假設我們有一個名為 Task 的 Entity,它有一個 title(String)屬性和一個 isCompleted(Boolean)屬性。

import CoreData

@objc(Task)
public class Task: NSManagedObject {
    @NSManaged public var title: String?
    @NSManaged public var isCompleted: Bool
}

3. 使用 @FetchRequest 來取得資料

在 SwiftUI 中,可以使用 @FetchRequest 來獲取 Task 資料並在視圖中顯示。下面是一個簡單的例子,將所有的 Task 資料顯示在 List 中:

import SwiftUI

struct TaskListView: View {
    // 使用 @FetchRequest 來自動從 Core Data 中獲取 Task 資料
    @FetchRequest(
        entity: Task.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Task.title, ascending: true)]
    ) var tasks: FetchedResults<Task>

    var body: some View {
        NavigationView {
            List {
                ForEach(tasks) { task in
                    HStack {
                        Text(task.title ?? "Untitled")
                        Spacer()
                        if task.isCompleted {
                            Image(systemName: "checkmark.circle")
                                .foregroundColor(.green)
                        }
                    }
                }
            }
            .navigationTitle("Tasks")
        }
    }
}

在這段程式碼中:

  • @FetchRequest 用於自動從 Core Data 中取得 Task 實體的資料。
  • entity: Task.entity() 指定了要獲取的實體是 Task
  • sortDescriptors 是一個排序描述符,用來定義資料的排序方式。在這裡,我們根據 title 屬性來排序。
  • tasks 是一個 FetchedResults<Task>,它像是陣列一樣,可以在 SwiftUI 視圖中直接使用。

4. 增加與刪除資料

除了顯示資料,你也可以在 SwiftUI 中使用 Core Data 的上下文來增加或刪除資料。以下是如何在 TaskListView 中增加一個任務:

struct TaskListView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(
        entity: Task.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \Task.title, ascending: true)]
    ) var tasks: FetchedResults<Task>

    var body: some View {
        NavigationView {
            List {
                ForEach(tasks) { task in
                    HStack {
                        Text(task.title ?? "Untitled")
                        Spacer()
                        if task.isCompleted {
                            Image(systemName: "checkmark.circle")
                                .foregroundColor(.green)
                        }
                    }
                }
                .onDelete(perform: deleteTasks) // 刪除功能
            }
            .navigationTitle("Tasks")
            .navigationBarItems(trailing: Button(action: addTask) {
                Label("Add Task", systemImage: "plus")
            })
        }
    }

    private func addTask() {
        withAnimation {
            let newTask = Task(context: viewContext)
            newTask.title = "New Task"
            newTask.isCompleted = false
            saveContext()
        }
    }

    private func deleteTasks(offsets: IndexSet) {
        withAnimation {
            offsets.map { tasks[$0] }.forEach(viewContext.delete)
            saveContext()
        }
    }

    private func saveContext() {
        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }
}

在這段程式碼中:

  • 使用 @Environment(\.managedObjectContext) 來取得當前的 Core Data 上下文。
  • addTask() 方法會在 viewContext 中新增一個 Task 實體並保存。
  • deleteTasks() 方法使用 onDelete 修飾符來刪除選定的任務。

5. 結論

以上的教學介紹了如何使用 @FetchRequest 來從 Core Data 中取得資料,並顯示在 SwiftUI 視圖中。這是 SwiftUI 與 Core Data 整合的強大功能之一,使得資料管理變得非常簡單且直觀。

這份教學也涵蓋了如何在 SwiftUI 中增加和刪除 Core Data 資料的基本操作。


上一篇
Day18 - URLSession 和 Codable,使用網路請求獲取資料
下一篇
Day 18: @Environment,使用環境變數
系列文
SwiftUI快速入門30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言